﻿using Dapper;
using guidHelper;
using Microsoft.AspNetCore.Mvc;
using MyDapperApi.Models;
using MyDapperApi.Services.QywxDocument.DigitalizationDemand;
using MyDapperApi.Services.QywxDocument.PrivateRoom;
using MySql.Data.MySqlClient;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using QYWXUpdate.DataModel;
using QYWXUpdate.DataModel.QYWXCallBack;
using QYWXUpdate.DataModel.QYWXDocument;
using System.Data;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using static MyDapperApi.Services.DateBaseService;

namespace MyDapperApi.Services;

public class QywxCallBackService : IQywxCallBackService
{
    private readonly IConfiguration _configuration;
    private readonly IDateBaseService _dateBaseService;
    private readonly IHttpClientFactory _httpClientFactory;
    //企业微信后台开发者设置的token, corpID, EncodingAESKey
    private readonly string sToken = "NO3Ma17gJk";//企业微信后台，开发者设置的Token
    private readonly string sCorpID = "ww41ce2a97523f4d1a";//企业号corpid是企业号的专属编号（CorpID）[不同场景含义不同，详见文档说明（ToUserName：企业微信的CorpID，当为第三方应用回调事件时，CorpID的内容为suiteid）]
    private readonly string sEncodingAESKey = "lhxbMEwEVPMADwKcC1jpiCSzF7yNkCqiEHwSclqBb0s";//企业微信后台，开发者设置的EncodingAESKey
    private readonly INetDocumentService _netDocumentService;
    private readonly IDocDigitalizationDemandService _docDigitalizationDemandService;
    private readonly IPrivateRoomService _privateRoomService;

    public QywxCallBackService(IConfiguration configuration,
        IDateBaseService dateBaseService,
        IHttpClientFactory httpClientFactory,
        INetDocumentService netDocumentService,
        IDocDigitalizationDemandService docDigitalizationDemandService,
        IPrivateRoomService privateRoomService)
    {
        _configuration = configuration;
        _dateBaseService = dateBaseService;
        _httpClientFactory = httpClientFactory;
        _netDocumentService = netDocumentService;
        _docDigitalizationDemandService = docDigitalizationDemandService;
        _privateRoomService = privateRoomService;
    }

    public async Task<CommonResponse> CallBackGet(QywxVerifyRequest request)
    {
        string signature = request.msg_signature;//微信加密签名，msg_signature结合了企业填写的token、请求中的timestamp、nonce参数、加密的消息体
        string timestamp = request.timestamp;//时间戳
        string nonce = request.nonce;//随机数

        var result = new CommonResponse();

        try
        {
            //在1秒内响应GET请求，响应内容为上一步得到的明文消息内容decryptEchoString（不能加引号，不能带bom头，不能带换行符）
            string echostr = request.echostr;//加密的随机字符串，以msg_encrypt格式提供。需要解密并返回echostr明文，解密后有random、msg_len、msg、$CorpID四个字段，其中msg即为echostr明文

            if (!string.IsNullOrWhiteSpace(signature) && !string.IsNullOrWhiteSpace(timestamp) && !string.IsNullOrWhiteSpace(nonce) && !string.IsNullOrWhiteSpace(echostr))
            {
                string decryptEchoString = null;
                if (CheckVerifyURL(sToken, signature, timestamp, nonce, sCorpID, sEncodingAESKey, echostr, ref decryptEchoString))
                {
                    if (!string.IsNullOrEmpty(decryptEchoString))
                    {
                        result.SetSuccess(decryptEchoString);
                        //必须要返回解密之后的明文
                        //return Content(decryptEchoString);
                    }
                }
            }
            else
            {
                result.SetError("fail");
            }
            return result;
        }
        catch (Exception ex)
        {
            result.SetError("fail");
        }

        result.SetError("fail");
        return result;
    }

    /// <summary>
    /// 验证URL有效性
    /// </summary>
    /// <param name="token">企业微信后台，开发者设置的Token</param>
    /// <param name="signature">签名串，对应URL参数的msg_signature</param>
    /// <param name="timestamp">时间戳</param>
    /// <param name="nonce">随机数</param>
    /// <param name="corpId">ToUserName为企业号的CorpID</param>
    /// <param name="encodingAESKey">企业微信后台，开发者设置的EncodingAESKey</param>
    /// <param name="echostr">随机串，对应URL参数的echostr</param>
    /// <param name="retEchostr">解密之后的echostr，当return返回0时有效</param>
    /// <returns></returns>
    private bool CheckVerifyURL(string token, string signature, string timestamp, string nonce, string corpId, string encodingAESKey, string echostr, ref string retEchostr)
    {
        WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAESKey, corpId);

        int result = wxcpt.VerifyURL(signature, timestamp, nonce, echostr, ref retEchostr);

        if (result != 0)
        {
            return false;//FAIL
        }

        //result==0表示验证成功、retEchostr参数表示明文
        //用户需要将retEchostr作为get请求的返回参数、返回给企业微信号
        return true;
    }

    /// <summary>
    /// 普通消息响应类型
    /// </summary>
    public enum ResponseMsgType
    {
        /// <summary>
        /// 文本消息
        /// </summary>
        Text = 0,
        /// <summary>
        /// 图文消息
        /// </summary>
        News = 1,
        /// <summary>
        /// 图片消息
        /// </summary>
        Image = 3,
        /// <summary>
        /// 语音消息
        /// </summary>
        Voice = 4,
        /// <summary>
        /// 视频消息
        /// </summary>
        Video = 5,
        Event = 6,
    }

    /// <summary>
    /// 第三方应用授权推送消息类型
    /// </summary>
    public enum ResponseInfoType
    {
        /// <summary>
        /// 推送suite_ticket 企业微信服务器会定时（每十分钟）推送ticket。ticket会实时变更，并用于后续接口的调用。
        /// </summary>
        suite_ticket = 1,

        /// <summary>
        /// 授权成功通知
        /// </summary>
        create_auth = 2,

        /// <summary>
        /// 成员通知事件
        /// </summary>
        change_contact = 3
    }

    /// <summary>
    /// 响应应答处理
    /// </summary>
    /// <param name="sMsg">解密参数</param>
    /// <param name="timestamp">时间戳</param>
    /// <param name="signature">签名</param>
    /// <param name="sToken">企业微信后台，开发者设置的Token</param>
    /// <param name="sEncodingAESKey">开发者设置的EncodingAESKey</param>
    /// <param name="sCorpID">业号corpid是企业号的专属编号（CorpID）</param>
    /// <returns></returns>
    public async Task<string> ReceiveResponse(string sMsg, string timestamp, string signature, string sToken, string sEncodingAESKey, string sCorpID)
    {
        string responseMessage = "success";//响应内容   
        var xmlDoc = XDocument.Parse(sMsg);//xml数据转化

        //区分普通消息与第三方应用授权推送消息，MsgType有值说明是普通消息，反之则是第三方应用授权推送消息
        if (xmlDoc.Root.Element("MsgType") != null)
        {
            //_dateBaseService.CreateLog("CallBack", xmlDoc.Root.Element("ChangeType").Value, sMsg, 1);
            var msgType = (ResponseMsgType)Enum.Parse(typeof(ResponseMsgType), xmlDoc.Root.Element("MsgType").Value, true);
            switch (msgType)
            {
                case ResponseMsgType.Text://文本消息
                    responseMessage = ResponseMessageText(xmlDoc, timestamp, signature, sToken, sEncodingAESKey, sCorpID);
                    break;
                case ResponseMsgType.Image:
                    responseMessage = ResponseDefault();
                    break;
                case ResponseMsgType.Voice:
                    responseMessage = ResponseDefault();
                    break;
                case ResponseMsgType.Video:
                    responseMessage = ResponseDefault();
                    break;
                case ResponseMsgType.News:
                    responseMessage = ResponseDefault();
                    break;
                case ResponseMsgType.Event:
                    {
                        var resEvent = xmlDoc.Root.Element("Event").Value ?? string.Empty;

                        switch (resEvent)
                        {
                            case "smart_sheet_change"://智能表格更新
                                {
                                    var sheetId = xmlDoc.Root.Element("SheetId").Value ?? string.Empty;
                                    var recordId = xmlDoc.Root.Element("RecordId").Value ?? string.Empty;
                                    var changeType = xmlDoc.Root.Element("ChangeType").Value ?? string.Empty;
                                    var docId = xmlDoc.Root.Element("DocId").Value ?? string.Empty;
                                    if (docId == "dcE-wSUE1WnAQ4vtPfjfZwu-a93Zw-Pr8HsigbTsNQ7zE33r-vV5R5ijVHSIaDm3Vs3nsHaPOnk4pNz2_PRcaPgQ")//安全巡检表格
                                    {
                                        await _netDocumentService.SelectSaveRecordChangeType(sheetId, recordId, changeType);
                                    }
                                    if (docId == "dcPfyR993e_EoTVs6XGZFI8ayHf68-WD-tAPeCZeAX2rFfKeMPq3iSHCWZgI_QyEOxuVjJ2XXhUdClRzYUtfXR5g")//企业微信需求
                                    {
                                        await _docDigitalizationDemandService.UpdateQywxWorkBanch(recordId);
                                    }
                                    if (docId == "dcg-khAYWolnB_wv842q_7l83alf3SUWGTCz8cHl5bPgOxNT0FXrH-ftRssUi6PEO11xZVf0D1HCPDZS4qxyK_5Q")//企业微信餐包
                                    {
                                        if (changeType == "delete_record")
                                        {
                                            await _privateRoomService.DeleteRecord(recordId);
                                        }
                                        else
                                            await _privateRoomService.GetRecordDetail(recordId);
                                    }
                                    break;
                                }
                        }

                        responseMessage = ResponseDefault();
                        break;
                    }
            }
        }
        else if (xmlDoc.Root.Element("InfoType") != null)
        {
            //第三方回调
            var infoType = (ResponseInfoType)Enum.Parse(typeof(ResponseInfoType), xmlDoc.Root.Element("InfoType").Value, true);

            switch (infoType)
            {
                case ResponseInfoType.suite_ticket:
                    {
                        //LoggerHelper._.Warn("suite_ticket===>>>>>,进来了，获取到的SuiteTicket票据为" + xmlDoc.Root.Element("SuiteTicket").Value);
                    }
                    break;
            }
        }
        else
        {
            //其他情况
        }

        // result==0表示解密成功，sMsg表示解密之后的明文xml串
        //服务器未正确返回响应字符串 “success”
        return responseMessage;
    }


    #region 相关事件实现

    /// <summary>
    /// 消息文本回复
    /// </summary>
    /// <returns></returns>
    public string ResponseMessageText(XDocument xmlDoc, string timestamp, string nonce, string sToken, string sEncodingAESKey, string sCorpID)
    {
        string FromUserName = xmlDoc.Root.Element("FromUserName").Value;
        string ToUserName = xmlDoc.Root.Element("ToUserName").Value;
        string Content = xmlDoc.Root.Element("Content").Value;

        string xml = "<xml>";
        xml += "<ToUserName><![CDATA[" + ToUserName + "]]></ToUserName>";
        xml += "<FromUserName><![CDATA[" + FromUserName + "]]></FromUserName>";
        xml += "<CreateTime>" + GetCurrentTimeUnix() + "</CreateTime>";
        xml += "<MsgType><![CDATA[text]]></MsgType>";
        xml += "<Content><![CDATA[" + Content + "]]></Content>";
        xml += "</xml>";
        //"" + Content + "0";//回复内容 FuncFlag设置为1的时候，自动星标刚才接收到的消息，适合活动统计使用
        WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID);
        string sEncryptMsg = "";// 加密后的可以直接回复用户的密文;
        wxcpt.EncryptMsg(xml, timestamp, nonce, ref sEncryptMsg);

        //返回
        return sEncryptMsg;
    }

    /// <summary>
    /// 图片消息
    /// </summary>
    /// <returns></returns>

    public string ResponseDefault()
    {
        return "success";
    }
    #endregion

    /// <summary>
    /// 获取当前时间戳
    /// </summary>
    /// <returns></returns>
    public static string GetCurrentTimeUnix()
    {
        TimeSpan cha = (DateTime.Now - TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)));
        long t = (long)cha.TotalSeconds;
        return t.ToString();
    }
}